﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ERF;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace FirstPerson.Objects {
    /// <summary>
    /// Represents a 3D plane.
    /// </summary>
    class Plane : GeometricGameObject {
        private static VertexPositionNormalTexture[] vertices;
        private static ushort[] indices;

        /// <summary>
        /// Creates a new plane, with a normal facing straight up.
        /// </summary>
        /// <param name="game">The game that this instance belongs to.</param>
        public Plane(ERFGame game)
            : base(game) {
            if (Plane.vertices == null) {
                this.CreateVertices(out Plane.vertices);
                this.CreateIndices(out Plane.indices);
            }
            base.Vertices = Plane.vertices;
            base.Indices = Plane.indices;
            base.PrimitiveCount = Plane.indices.Length / 3;
            base.PrimitiveType = PrimitiveType.TriangleList;
        }

        /// <summary>
        /// Creates a new plane with the given normal.
        /// </summary>
        /// <param name="game">The game that this instance belongs to.</param>
        /// <param name="normal">The normal that defines the rotation of this plane.</param>
        public Plane(ERFGame game, Vector3 normal) : base(game)
        {
            if (Plane.indices == null)
            {
                this.CreateIndices(out Plane.indices);
            }
            normal.Normalize();
            Vector3 z = Vector3.UnitZ;
            Vector3 side1, side2;
            Vector3.Cross(ref normal, ref z, out side1);
            side1.Normalize();
            Vector3.Cross(ref normal, ref side1, out side2);
            float lowZ = side2.Z;
            float highZ = -side2.Z;
            float lowX = -side1.X;
            float highX = side1.X;
            float lowY = -side1.Y;
            float highY = side1.Y;

            base.Vertices = new VertexPositionNormalTexture[]{
                new VertexPositionNormalTexture(new Vector3(lowX, highY, lowZ), normal, Vector2.Zero),
                new VertexPositionNormalTexture(new Vector3(highX, highY, lowZ), normal, new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(lowX, lowY, highZ), normal, new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(highX, lowY, highZ), normal, new Vector2(1, 1))
            };

            base.Indices = Plane.indices;

            base.PrimitiveCount = Plane.indices.Length / 3;
            base.PrimitiveType = PrimitiveType.TriangleList;
        }

        /// <summary>
        /// Creates the vertices for the plane.
        /// </summary>
        /// <param name="vertices">Will contain the vertice array when this method call returns.</param>
        private void CreateVertices(out VertexPositionNormalTexture[] vertices) {
            vertices = new VertexPositionNormalTexture[] {
                new VertexPositionNormalTexture(
                    new Vector3(-0.5f,0,-0.5f),
                    Vector3.Up,
                    Vector2.Zero),
                new VertexPositionNormalTexture(
                    new Vector3(0.5f, 0, -0.5f),
                    Vector3.Up,
                    new Vector2(1,0)),
                new VertexPositionNormalTexture(
                    new Vector3(-0.5f, 0, 0.5f),
                    Vector3.Up,
                    new Vector2(0,1)),
                new VertexPositionNormalTexture(
                    new Vector3(0.5f, 0, 0.5f),
                    Vector3.Up,
                    new Vector2(1,1))};
        }

        /// <summary>
        /// Creates the indices for the plane.
        /// </summary>
        /// <param name="indices">Will contain an array of ushort indices when the method call returns.</param>
        private void CreateIndices(out ushort[] indices) {
            indices = new ushort[]{
                0,1,2,
                1,3,2};
        }

        public override void Update(GameTime gameTime, ref Matrix world) {
            base.UpdateWorld(ref world);
            base.Update(gameTime, ref world);
        }
    }
}
